--
-- Rotor module interface definition
--

--
-- Local refrences to global objects
--
local Rotor = _G['Rotor']

--
-- Create new Rotor module with default impelmentation of interface functions
--
local function newModuleInstance(mod_name) return {

    --
    -- Answer module name
    --
    -- arguments:
    --      none
    --  returns:
    --      module name <string>
    --
    Name = function(self)
        return mod_name
    end,

    --
    -- Register module within Rotor
    --
    -- arguments:
    --      none
    -- returns:
    --      none
    --
    Register = function(self)
        Rotor:RegisterModule(self)
    end,

    --
    -- Unregister module from Rotor
    --
    Unregister = function(self)
        Rotor:UnregisterModule(self)
    end,

    --
    -- Detect module usability for current spec
    --
    Detect = function(self)
        return false
    end,

    --
    -- Initialize module
    --
    -- arguments:
    --      options<table> - table of module options (persist between logons)
    -- return:
    --      true - module successfully initialized
    --      false/nil, failure_reason<string> - initialization failed. failure_reason is optional
    --
    Init = function(self, options)
        return nil, 'Init function is not defined for module "'..mod_name..'"'
    end,

    --
    -- Finalize module before switching to new (possible this) module
    --
    -- arguments:
    --      new_module - module which will be used after this module (may be this module)
    -- returns:
    --      none
    Done = function(self, new_module)
        -- do nothing by default
    end,

    --
    -- Choose next skill.
    --
    -- arguments:
    --      gcd<float> - remain GCD time in seconds with fractional part
    --      cur_skill - currently displayed skill, still waiting to send or 0 if send wait is over
    -- return
    --      next skill ID or 0 if no next skill
    --
    NextSkill = function(self, gcd, cur_skill)
        return 0
    end,

    --
    -- Notify module about sent cast
    --
    -- arguments:
    --      spell_name<string> - the name of sent spell
    -- return:
    --      none
    --
    CastSent = function(self, spell_name) end,

    --
    -- Notify module about send done (UNIT_SPELLCAST_SUCCEED, UNIT_SPELLCAST_FAILED, UNIT_SPELLCAST_INTERRUPTED, UNIT_SPELLCAST_FAILED_QUIET)
    --
    -- arguments:
    --      spell_name - the name of finished spell
    --      is_success - true if sent successfull, false otherwise
    --      failire_reason - on failed cast one of following: FAILED_QUIET, FAILED, INTERRUPTED, DELAYED (depends on event type)
    -- return:
    --      true if next spell should NOT be chosen
    --
    CastFinished = function(self, spell_name, is_success, failure_reason) return false end,

    --
    -- Update function. Called when frame OnUpdate event occured.
    --
    -- arguments:
    --      elapsed<float> - time in seconds since last call to Update
    -- return:
    --      none
    --
    Update = function(self, elapsed) end,

    --
    -- Notify module about inventory change.
    --
    -- arguments:
    --      none
    -- return:
    --      true if next skill should be chosen, false otherwise
    --
    InventoryChanged = function(self) return false end,

    --
    -- Notify module about target changed.
    --
    -- arguments:
    --      old_target_guid - GUID of previous valid target
    -- return:
    --      none
    TargetChanged = function(self, old_target_guid) end,

    --
    -- Notify module when unit is entering or leaving combat
    --
    -- arugments:
    --      none
    -- return:
    --      none
    --
    CombatStateChanged = function(self) end,

    --
    -- Called when spell usablity needed to be checked.
    --
    -- arguments:
    --      spell_id - id of spell being checked (usually currently suggested spell)
    -- return:
    --      true - spell is usable, false otherwise
    --
    CheckUsable = function(self, spell_id) return Rotor:defaultUsableCheck(spell_id) end,

    --
    -- Called when spell range needed to be checked.
    --
    -- arguments:
    --      spell_id - id of spell being checked (usually currently suggested spell)
    -- return:
    --      true - spell is in range (or range is not important), false otherwise
    --
    CheckInRange = function(self, spell_id) return Rotor:defaultRangeCheck(spell_id) end,

    --
    -- Handle commands from command line. called when /rr opt ... is executed
    --
    -- arguments:
    --      cmd_line<string> - text after '/rr opt'
    -- return:
    --      true - module reinitialization required, false otherwise
    --
    HandleCommandLine = function(self, cmd_line)
        Rotor:Print('Module "'..mod_name..'" does not have options')
        return false
    end,

    --
    -- Answer time to wait for send suggested spell after gcd ends.
    --
    -- arguments:
    --      spell_id - id of current spell
    -- returns:
    --      time in seconds to wait or nil if use default time
    --
    TimeToWaitOfSend = function(self, spell_id)
        return nil
    end,

    --
    -- Sent when power display is updated
    --
    PowerDisplayUpdated = function(self)
    end,
}
end

----------------------------------------
--
-- Create and register new rotation module
--
function Rotor:NewModule(mod_name)
    if self.modules[mod_name] then
        error('module "'..mod_name..'" alredy exists')
    end

    local m = newModuleInstance(mod_name)

    self.modules[mod_name] = m
    return m
end
----------------------------------------
function Rotor:saveModuleOptions(opts)
    if not self.cfg.module_opts then
        self.cfg.module_opts = {}
    end
    self.cfg.module_opts[self.cur_mod:Name()] = opts
end
